/* circular-stack.vala
 *
 * Copyright (C) 2010  Richard Talbot-Watkins
 * Copyright (C) 2010  Dave Jeffery
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Authors:
 *  Richard Talbot-Watkins <richtw1@gmail.com>
 * 	Dave Jeffery <david.richard.jeffery@gmail.com>
 */

/**
 * The purpose of this class is to provide a circular stack for the undo and
 * redo functions. A circular stack is a stack with a fixed number of places,
 * that just throws the oldest data away when it becomes full.
 *
 * @author Richard Talbot-Watkins <richtw1@gmail.com>
 * @author Dave Jeffery <david.richard.jeffery@gmail.com>
 * @version 2010.1225
 * @since 0.1
 */
public class MonsterDesigner.CircularStack<T> : GLib.Object {

	/**
	 * The maximum number of elements on the stack.
	 */
    private int stack_size;

	/**
	 * The position of the top of the stack.
	 */
    private int top = 0;

	/**
	 * Used to store the array that holds the stack.
	 */
    private T[] stack;

	/**
	 * Stores the number of elements in the stack.
	 */
    private int _count = 0;

	/**
	 * Getter for the stack property. 
	 * 
	 * The absence of a setter block denotes it is "private set".
	 */
    public int count {
        get { return _count; }
    }

	/**
	 * Constructor for a circular stack.
	 *
	 * @param size Size of the circular stack.
	 */
    public CircularStack (int size=32)
    {
        stack_size = size;
        stack = new T[stack_size];
    }

	/**
	 * Pushes an item onto the circular stack.
	 */
    public void push (T item) {
        stack[top] = item;
        top = (top + 1) % stack_size;
        if (_count < stack_size) {
            _count++;
        }
    }

	/**
	 * Pops an item off of the circular stack.
	 *
	 * Note that Vala doesn't have a default() function for returning the
	 * default value for a type. Luckily, null will suffice in all cases.
	 *
	 * @return An object of type <T>.
	 */
	public T pop () throws StackError {
		if (count == 0) {
			throw new StackError.STACK_EMPTY
				("The stack is empty.");
		} else {
			_count--;
			top = (top + stack_size - 1) % stack_size;
			T item = stack[top];
			stack[top] = null;
			return item;
		}
	}

	/**
	 * Clears the stack.
	 *
	 * Note that Vala doesn't have C#'s "Initialize()" function.
	 */
    public void clear () {
        stack = new T[stack_size];
        _count = 0;
        top = 0;
    }
}

